package NonBinaryAttributes;
import java.util.ArrayList;
import java.util.HashMap;


public class GlobalTransactionList {
	private ArrayList<Transaction> transactions;
	private static GlobalTransactionList instance;
	private GlobalItemList gil;
	private HashMap<Integer, String> mappings;
	
	private GlobalTransactionList() {
		transactions = new ArrayList<Transaction>();
		gil = GlobalItemList.getInstance();
		mappings = new HashMap<Integer, String> ();
	}
	
	public static GlobalTransactionList getInstance() {
		if(instance == null) {
			instance = new GlobalTransactionList();
		}
		return instance;
	}

	public void addTransaction(String read) {
		Transaction newTrans = new Transaction();
		transactions.add(newTrans);
		String[] data = read.split(", ");
		for(int i = 0; i < data.length; ++i) {
			String value = data[i];
			ArrayList<Integer> converted = binarize(i, value); 
			if(converted.size() > 0) {
				for(Integer item:converted) {
					gil.addItem(item);
					newTrans.addItem(item);
				}
			}
		}
	}
	
	private ArrayList<Integer> binarize(int index, String value) {
		ArrayList<Integer> toReturn = new ArrayList<Integer>();
		if(value.equals("?")) {
			return toReturn;
		}
		int base = index*1000;
		int result, result2 = -1;
		int binSize, binSize2;
		switch(index) {
		case 0: //age
			binSize = 20;
			binSize2 = 40;
			result = Integer.valueOf(value) /binSize; 
			result2 = Integer.valueOf(value) /binSize2;
			mappings.put(base + result, "AGE"+result*binSize + "-" + ((result+1)*binSize-1));
			mappings.put(base + binSize2 + result2, "AGE"+result2*binSize2 + "-" + ((result2+1)*binSize2-1));
			toReturn.add(base+result);
			toReturn.add(base+binSize2 + result2);
		break;
		case 1: //workclass
			String[] possibilitiesWork = {"Private", "Self-emp-not-inc", "Self-emp-inc", 
					"Federal-gov", "Local-gov", "State-gov", "Without-pay", "Never-worked"};
			
			result = indexOfPossibleValue(possibilitiesWork, value);
			if(result >= 3 && result <= 5) {
				mappings.put(base+result+possibilitiesWork.length, "WORK=GOV");
				toReturn.add(base+result+possibilitiesWork.length);
			} else {
				mappings.put(base+result+possibilitiesWork.length+1, "WORK=NONGOV");
				toReturn.add(base+result+possibilitiesWork.length+1);
			}
			mappings.put(base+result, "WORK="+value);
			toReturn.add(base+result);
			break;
		case 2: //fnlwgt, ignored
			break;
		case 3: //studies
			String[] possibilitiesStudies = {"Some-college","Bachelors", "Masters", "Doctorate", "11th", "HS-grad", "Prof-school",
					"Assoc-acdm", "Assoc-voc", "9th","7th-8th", "12th", "1st-4th", "10th", "5th-6th", "Preschool"};
			result = indexOfPossibleValue(possibilitiesStudies, value);
			mappings.put(base+result, "STUDIES="+value);
			toReturn.add(base+result);
			if(result <=3) {
				mappings.put(base+result+possibilitiesStudies.length, "COLLEGE=YES");
				toReturn.add(base+result+possibilitiesStudies.length);
			} else {
				mappings.put(base+result+possibilitiesStudies.length+1, "COLLEGE=NO");
				toReturn.add(base+result+possibilitiesStudies.length+1);
			}
			break;
		case 4: //education num
			mappings.put(base + Integer.valueOf(value), "EDUNUM="+value);
			toReturn.add(base + Integer.valueOf(value));
			break;
		case 5: //marital status
			String[] possibilitiesMarital = {"Divorced", "Never-married", "Separated", "Widowed", 
					"Married-civ-spouse", "Married-spouse-absent", "Married-AF-spouse"};
			result = indexOfPossibleValue(possibilitiesMarital, value);
			mappings.put(base+result, "MARITAL="+value);
			toReturn.add(base+result);
			if(result >= 4) {
				mappings.put(base+result+possibilitiesMarital.length, "MARRIED=YES");
				toReturn.add(base+result+possibilitiesMarital.length);
			}
			break;
		case 6: //occupation
			String[] possibilitiesOccupation = {"Tech-support", "Craft-repair", "Other-service", "Sales",
					"Exec-managerial", "Prof-specialty", "Handlers-cleaners", "Machine-op-inspct", "Adm-clerical",
					"Farming-fishing", "Transport-moving", "Priv-house-serv", "Protective-serv", "Armed-Forces"};
			result = indexOfPossibleValue(possibilitiesOccupation, value);
			mappings.put(base+result, "OCCUPATION="+value);
			toReturn.add(base+result);
			break;
		case 7: //relationship
			String[] possibilitiesRelationship = {"Wife", "Own-child", "Husband", "Not-in-family", "Other-relative", "Unmarried"};
			result = indexOfPossibleValue(possibilitiesRelationship, value);
			mappings.put(base+result, "RELATIONSHIP="+value);
			toReturn.add(base+result);
			break;
		case 8: //race
			String[] possibilitiesRace = {"White", "Asian-Pac-Islander", "Amer-Indian-Eskimo", "Other", "Black"};
			result = indexOfPossibleValue(possibilitiesRace, value);
			mappings.put(base+result, "RACE="+value);
			toReturn.add(base+result);
			break;
		case 9: //sex
			String[] possibilitiesSex = {"Female", "Male"};
			result = indexOfPossibleValue(possibilitiesSex, value);
			mappings.put(base+result, "SEX="+value);
			toReturn.add(base+result);
			break;
		case 10: //capital gain
			binSize = 10000;
			binSize2 = 50000;
			result = Integer.valueOf(value) /binSize;
			mappings.put(base + result, "CAPITALGAIN="+result*binSize + "-" + ((result+1)*binSize-1));
			result2 = Integer.valueOf(value) /binSize2;
			mappings.put(base + result2+500, "CAPITALGAIN="+result2*binSize2 + "-" + ((result2+1)*binSize2-1));
			toReturn.add(base+result2 + 500);
			break;
		case 11: //capital loss
			binSize = 1000;
			binSize2 = 2000;
			result = Integer.valueOf(value) /binSize; 
			mappings.put(base + result, "CAPITALLOSS="+result*binSize + "-" + ((result+1)*binSize-1));
			toReturn.add(base+result);
			result2 = Integer.valueOf(value) /binSize2; 
			mappings.put(base + result2 + 500, "CAPITALLOSS="+result2*binSize2 + "-" + ((result2+1)*binSize2-1));
			toReturn.add(base+result2 + 500);
			break;
		case 12: //hours/week
			binSize = 10;
			binSize2 = 41; //0-40, > 40
			result = Integer.valueOf(value) /binSize; 
			mappings.put(base + result, "WORKHOURS="+result*binSize + "-" + ((result+1)*binSize-1));
			toReturn.add(base+result);
			result2 = Integer.valueOf(value) /binSize2; 
			mappings.put(base + result2 + 500, "WORKHOURS="+result2*binSize2 + "-" + ((result2+1)*binSize2-1));
			toReturn.add(base+result2 +500);
			break;
		case 13: //native country
			String[] possibilitiesCountries = {"United-States", "Cambodia", "England", "Puerto-Rico", "Canada", "Germany", 
			"Outlying-US(Guam-USVI-etc)", "India", "Japan", "Greece", "South", "China", "Cuba", "Iran", "Honduras", 
			"Philippines", "Italy", "Poland", "Jamaica", "Vietnam", "Mexico", "Portugal", "Ireland", "France", 
			"Dominican-Republic", "Laos", "Ecuador", "Taiwan", "Haiti", "Columbia", "Hungary", "Guatemala", "Nicaragua", "Scotland", 
			"Thailand", "Yugoslavia", "El-Salvador", "Trinadad&Tobago", "Peru", "Hong", "Holand-Netherlands"}; 
			result = indexOfPossibleValue(possibilitiesCountries, value);
			mappings.put(base+result, "NATIVECOUNTRY="+value);
			toReturn.add(base+result);
			break;
		case 14: //income
			String[] possibilitiesIncome = {"<=50K", ">50K"};
			result = indexOfPossibleValue(possibilitiesIncome, value);
			mappings.put(base+result, "INCOME="+value);
			toReturn.add(base+result);
			break;
		}			
		return toReturn;
	}
	
	public String getMappedValue(int key) {
		return mappings.get(key);
	}

	private Integer indexOfPossibleValue(String[] possibilities, String value) {
		for(int i = 0; i < possibilities.length; ++i) {
			if(possibilities[i].equals(value)) {
				return i;
			}
		}
		return -Integer.MAX_VALUE;
	}

	public int getTotalTransactions() {
		return transactions.size();
	}

	public void printAllTransactions() {
		for(Transaction t:transactions) {
			t.printAllItems();
		}
	}

	public int calculateSupport(ArrayList<Item> items) {
		int support = 0;
		for(Transaction t:transactions) {
			if(t.containsAll(items)) {
				support++;
			}
		}
		return support;
		
	}
}
